package com.itheima.aspect;

import com.google.gson.Gson;
import com.itheima.pojo.log.EmpLog;
import com.itheima.service.EmpLogService;
import com.itheima.utils.EmpContext;
import jakarta.servlet.http.HttpServletRequest;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.Objects;

/**
 * 控制器日志切面
 */
@Aspect
@Component
public class ControllerLogAspect {

    @Autowired
    private EmpLogService empLogService;

    @Autowired
    private Gson gson;

    // 定义切点：拦截所有控制器的方法
    @Pointcut("execution(* com.itheima.controller.*.*(..))")
    public void controllerPointcut() {
    }

    @Around("controllerPointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        // 获取当前请求
        HttpServletRequest request =
                ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
        String method = request.getMethod(); // 获取请求方法（GET、POST、PUT、DELETE等）

        // 只记录增删改操作（POST、PUT、DELETE）
        if (!"GET".equalsIgnoreCase(method)) {
            // 获取方法签名
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            // 获取方法名称
            String methodName = signature.getName();
            // 获取类名
            String className = joinPoint.getTarget().getClass().getName();

            long startTime = System.currentTimeMillis();
            Object result = null;
            // 记录执行成功与否
            boolean isSuccess = true;

            try {
                // 执行目标方法
                result = joinPoint.proceed();
            } catch (Exception e) {
                isSuccess = false;
                throw e;
            } finally {
                long endTime = System.currentTimeMillis();
                // 计算耗时
                Long costTime = endTime - startTime;

                String methodParams = getMethodParams(joinPoint.getArgs());
                // 将返回值结果转换为JSON字符串
                String returnValue = result != null ? gson.toJson(result) : "void";

                // 创建日志对象
                EmpLog empLog = new EmpLog();
                empLog.setOperateEmpId(EmpContext.getCurrentEmpId());
                empLog.setOperateTime(LocalDateTime.now());
                empLog.setClassName(className);
                empLog.setMethodName(methodName);
                empLog.setMethodParams(methodParams);
                empLog.setReturnValue(returnValue);
                empLog.setCostTime(costTime);
                empLog.setInfo("操作：" + className + "." + methodName + (isSuccess ? " 成功" : " 失败"));

                // 记录日志
                empLogService.insertLog(empLog);
            }

            return result;
        } else {
            // 如果是GET请求，直接执行目标方法，不记录日志
            return joinPoint.proceed();
        }
    }

    private String getMethodParams(Object[] args) {
        if (args == null || args.length == 0) {
            return "无参数";
        }
        StringBuilder params = new StringBuilder();
        for (Object arg : args) {
            if (arg instanceof MultipartFile file) {
                // 如果是 MultipartFile 类型，提取文件名
                params.append("文件: ").append(file.getOriginalFilename()).append(", ");
            } else if (arg instanceof Integer[]) {
                // 如果是 Integer 数组，使用 Arrays.toString() 转换
                params.append(Arrays.toString((Integer[]) arg)).append(", ");
            } else {
                params.append(arg != null ? arg.toString() : "null").append(", ");
            }
        }
        // 移除最后一个逗号和空格
        return params.substring(0, params.length() - 2);
    }
}
